04 - 卸载到外部
前置:03 篇。压缩和裁剪都是有损的;本篇是第三种选择 —— 不砍,挪出去。
本篇回答:把内容放到上下文之外的三条路线各自怎么工作,以及它们分别把问题推到了哪里 —— 卸载不消灭成本,只是换一种形式付。
本篇会用到的词:
| 词 | 意思 |
|---|---|
| 卸载(offload) | 内容存在上下文之外,上下文里只留一个能取回它的指针 |
| 结构化笔记 | Agent 自己在外部维护的进度、决策、待办文件。它写,它自己读 |
| 子 Agent | 独立开一个上下文窗口去做某个子任务,只把结论返回给主 Agent |
| 即时检索 | 不预先把内容塞进上下文,等真正需要时再去取。区别于"启动时全部加载" |
| 指针 | 文件路径、记录 ID、URL 这类几十 token 的引用 |
一、共同结构:上下文里只留指针
三条路线的形式不同,骨架是一样的:
report.md 这样的名字模型没法判断该不该读;report_2026Q2_财务_含分季度明细.md 才能让它在不打开的情况下做决策。这一点和记忆专题 05 篇里"文件式记忆靠模型看文件名猜"是同一个约束。二、路线 A:结构化笔记
Agent 在外部维护一组自己写、自己读的文件:进度、已做的决策、待办、踩过的坑。
<!-- progress.md —— 每个会话开头读、结尾写 -->
# 当前任务:把订单服务从 REST 迁到 gRPC
## 已完成(端到端验证过才写进这里)
- [x] proto 定义 —— 见 `api/order.proto`
- [x] 服务端实现 —— 单测通过,集成测试通过
## 进行中
- [ ] 客户端迁移 —— 已改完 3 个调用方,还剩 `billing` 和 `notify`
## 已确定的约束(不要重新讨论)
- 保留 REST 端点到 2026-12-31,两套并存
- 不引入新的序列化库,用现有的 protobuf 版本
## 踩过的坑
- `billing` 的超 时是在网关侧配的,改客户端没用
三个设计要点:
- "已完成"的判据是端到端验证通过,不是代码写完。否则进度文件会越来越不可信,而它一旦不可信,整条路线就废了
- "已确定的约束"这一节比进度更重要。它防的是压缩之后模型重新讨论已经定过的事
- 一次只推进一个条目。同时开三件事,写回时容易把状态写乱
这条路线的实现形态在记忆专题 05 篇里讲透了(memory 工具的六个命令、路径穿越防护、Letta 的 git 版本化目录)。区别只在目的:那边关注跨会话保管,这边关注给当前上下文腾地方。
三、路线 B:子 Agent 隔离上下文
主 Agent 把一个需要大量阅读的子任务交给子 Agent,子 Agent 用自己独立的上下文窗口去做,只把结论返回来。Anthropic 给的返 回量级是 1,000 到 2,000 token。
代价要说清楚:
| 代价 | 具体 |
|---|---|
| 信息压缩比极高 | 110K 压到 1.5K,压缩比约 70:1。主 Agent 拿不到细节,也没法追问原文 |
| 不可回溯 | 子 Agent 的上下文用完即弃。主 Agent 后来发现摘要里某句话可疑,没法回去看依据 |
| 总 token 没降 | 三份资料照样被完整读了一遍,只是读在别处 |
| 延迟可能更高 | 能并行时更快,不能并行时是串行叠加 |
| 调试变难 | 出问题时要看四条 trace 而不是一条 |
适用判据:子任务是"读大量内容、产出一个结论"这种形状,且结论本身足以支撑后续决策。如果主 Agent 后面还需要回到细节,这条路线就不合适 —— 改用路线 A(子 Agent 把细节写成文件,主 Agent 拿到路径)。